import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class ClientMain {
    public static void main(String[] args) throws IOException, InterruptedException {
        int port = Global.port;
        // init
        SocketChannel sc = SocketChannel.open();
        sc.configureBlocking(false);
        Selector selector = Selector.open();
        // register
        sc.register(selector, SelectionKey.OP_CONNECT);
        // connect
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", Global.port);
        boolean connect = sc.connect(inetSocketAddress);
//        if (connect) {
//            // register read
//            sc.register(selector, SelectionKey.OP_READ);
//            // write
//            String req = "query time order.";
//            byte[] reqBytes = req.getBytes();
//            ByteBuffer writeBuffer = ByteBuffer.allocate(reqBytes.length);
//            writeBuffer.put(reqBytes);
//            writeBuffer.flip();
//            sc.write(writeBuffer);
//        } else {
//            // register connect
//            sc.register(selector, SelectionKey.OP_CONNECT);
//        }
        boolean isFirstWrite = true;
        boolean isListeningResp = true;
        while (true) {
            // select key
            selector.select(1000); // must call first.
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> it = selectionKeys.iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                if (key.isValid()) {
                    if (key.isConnectable()) {
                        // get channel
                        SocketChannel channel = (SocketChannel) key.channel();
                        // check if connect finished
                        boolean isFinishedConnect = false;
                        try {
                            isFinishedConnect = channel.finishConnect();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        if (isFinishedConnect) {
                            // register read update
                            channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                            System.out.println("wait to write or read");
                        } else {
                            System.out.println("fail to connect to server.");
                            Thread.sleep(3000);// try again
//                            System.exit(1);  // try again
                        }
                    } else if (key.isReadable()) {
                        // get channel
                        SocketChannel channel = (SocketChannel) key.channel();
                        // read buf
                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        // read
                        int count = channel.read(readBuffer);
                        // resp logic
                        if (count > 1) {
                            readBuffer.flip();
                            byte[] readBytes = new byte[count];
                            readBuffer.get(readBytes);
                            String resp = new String(readBytes, "UTF-8");
                            System.out.println("recv from server:" + resp);
                        } else if (count < 0) {
                            System.out.println("server not available ");
                            key.cancel();
                            channel.close(); // reuse to reconnect
//                            break; // skip left
                        } else {
                            // skip.
                            System.out.println("skipped");
                        }
                        if (isListeningResp) {
                            isListeningResp = false;
                        }
                    } else if (key.isWritable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        if (isFirstWrite) {
                            // write
                            String req = "query time order.";
                            byte[] reqBytes = req.getBytes();
                            ByteBuffer writeBuffer = ByteBuffer.allocate(reqBytes.length);
                            writeBuffer.put(reqBytes);
                            writeBuffer.flip();
                            channel.write(writeBuffer);
                            isFirstWrite = false;
                        } else if (!isListeningResp) {
                            // read input and write
                            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                            String line = reader.readLine();
                            isListeningResp = true;
                            if (line != null && !line.trim().equals("")) {
                                byte[] lineBytes = line.getBytes();
                                ByteBuffer writeBuffer = ByteBuffer.allocate(lineBytes.length);
                                writeBuffer.put(lineBytes);
                                writeBuffer.flip();
                                channel.write(writeBuffer);
                            }
                        }
                    }
                } else {
                    System.out.println("key is not valid");
                }
            }
            if (!sc.isConnected()) {
                System.out.println("try to reconnect");
                sc = SocketChannel.open();
                sc.configureBlocking(false);
                sc.register(selector, SelectionKey.OP_CONNECT);
                sc.connect(inetSocketAddress);
                // reset
                isFirstWrite = true;
                isListeningResp = true;
            }
        }
    }
}
